export default class SnapManager {
    constructor(d3, canvas, guideline, config = {}) {
        this.d3Instance = d3;
        this.canvas = canvas;
        this.guideline = guideline;
        this.SNAP_DISTANCE = config.SNAP_DISTANCE || 20;
        this.SNAP_STRENGTH = config.SNAP_STRENGTH || 0.8; // 吸附强度，0-1之间，1表示完全吸附
        this.SNAP_THRESHOLD = config.SNAP_THRESHOLD || 0.5; // 吸附阈值，决定何时应用吸附
        this.MAX_SPEED_FOR_SNAP = config.MAX_SPEED_FOR_SNAP || 2; // 应用吸附的最大速度
        this.dragOffset = {
            x: 0,
            y: 0
        };
        this.lastPosition = { x: 0, y: 0 };
        this.lastTime = 0;
        this.isMoving = false;
        this.stopMoveTime = 0;
    }

    updateOffset = (event, selection) => {
        const transform = this.d3Instance.zoomTransform(this.canvas.node());
        const point = this.d3Instance.pointer(event, this.canvas.node());
                            
        // 正确计算反转变换的点
        const invertedX = (point[0] - transform.x) / transform.k;
        const invertedY = (point[1] - transform.y) / transform.k;

        const elementX = Number(selection.attr('x'));
        const elementY = Number(selection.attr('y'));
                            
        this.dragOffset.x = this.ensureNumber(invertedX - elementX);
        this.dragOffset.y = this.ensureNumber(invertedY - elementY); 
    } 

    ensureNumber = (value, defaultValue = 0) => {
        return isNaN(value) ? defaultValue : value;
    };

    checkSnap = (element, elements) => {
        const snaps = [];

        const currentX = Number(element.attr('x'));
        const currentY = Number(element.attr('y'));
        const currentWidth = Number(element.attr('width'));
        const currentHeight = Number(element.attr('height'));

        const current = {
            left: currentX,
            right: currentX + currentWidth,
            top: currentY,
            bottom: currentY + currentHeight,
            centerX: currentX + currentWidth / 2,
            centerY: currentY + currentHeight / 2
        };
        
        // 性能优化：只检查视口内的元素
        const visibleElements = this.getVisibleElements(elements);
        
        visibleElements.each(target => {
            const newTarget = target.selection;
            const targetId = newTarget.attr('data-class-common-key');
            const elementId = element.attr('data-class-common-key');
            if (targetId === elementId) return;

            // target: 视口内的其他元素
            const x = Number(newTarget.attr('x'));
            const y = Number(newTarget.attr('y'));
            const width = Number(newTarget.attr('width'));
            const height = Number(newTarget.attr('height'));
            
            const targetRect = {
                left: x,
                right: x + width,
                top: y,
                bottom: y + height,
                centerX: x + width / 2,
                centerY: y + height / 2
            };
            
            // 检查各种对齐方式
            // 左对齐
            if (Math.abs(current.left - targetRect.left) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'left', value: targetRect.left, target });
            }
            
            // 右对齐
            if (Math.abs(current.right - targetRect.right) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'right', value: targetRect.right - element.width, target });
            }
            
            // 顶对齐
            if (Math.abs(current.top - targetRect.top) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'top', value: targetRect.top, target });
            }
            
            // 底对齐
            if (Math.abs(current.bottom - targetRect.bottom) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'bottom', value: targetRect.bottom - element.height, target });
            }
            
            // 水平居中对齐
            if (Math.abs(current.centerX - targetRect.centerX) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'centerX', value: targetRect.centerX - element.width / 2, target });
            }
            
            // 垂直居中对齐
            if (Math.abs(current.centerY - targetRect.centerY) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'centerY', value: targetRect.centerY - element.height / 2, target });
            }
            
            // 当前元素左边缘吸附到目标元素右边缘
            if (Math.abs(current.left - targetRect.right) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'leftToRight', value: targetRect.right, target });
            }
            
            // 当前元素右边缘吸附到目标元素左边缘
            if (Math.abs(current.right - targetRect.left) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'rightToLeft', value: targetRect.left - element.width, target });
            }
            
            // 当前元素上边缘吸附到目标元素下边缘
            if (Math.abs(current.top - targetRect.bottom) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'topToBottom', value: targetRect.bottom, target });
            }
            
            // 当前元素下边缘吸附到目标元素上边缘
            if (Math.abs(current.bottom - targetRect.top) < this.SNAP_DISTANCE) {
                snaps.push({ type: 'bottomToTop', value: targetRect.top - element.height, target });
            }
        });
        
        return snaps;
    }
        
    // 性能优化：只获取视口内的元素
    getVisibleElements = (elements) => {
        const canvasRect = this.canvas.node().getBoundingClientRect();
        return elements.filter(el => {
            return !(
                el.x + el.width < 0 ||
                el.x > canvasRect.width ||
                el.y + el.height < 0 ||
                el.y > canvasRect.height
            );
        });
    }
    
    applySnaps = (element, snaps) => {
        let newX = Number(element.attr('x'));
        let newY = Number(element.attr('y'));
        const appliedSnaps = [];
        
        // 找到最强的吸附（距离最近的）
        let bestSnapX = null;
        let bestSnapY = null;
        let minDistanceX = Infinity;
        let minDistanceY = Infinity;
        
        snaps.forEach(snap => {
            switch(snap.type) {
                case 'left':
                case 'right':
                case 'rightToLeft':
                case 'leftToRight':
                case 'centerX':
                    const distanceX = Math.abs(newX - snap.value);
                    if (distanceX < minDistanceX) {
                        minDistanceX = distanceX;
                        bestSnapX = snap.value;
                    }
                    appliedSnaps.push(snap);
                    break;
                    
                case 'top':
                case 'bottom':
                case 'bottomToTop':
                case 'topToBottom':
                case 'centerY':
                    const distanceY = Math.abs(newY - snap.value);
                    if (distanceY < minDistanceY) {
                        minDistanceY = distanceY;
                        bestSnapY = snap.value;
                    }
                    appliedSnaps.push(snap);
                    break;
            }
        });
        
        // 应用最强的吸附
        if (bestSnapX !== null) {
            newX = this.ensureNumber(bestSnapX);
        }
        if (bestSnapY !== null) {
            newY = this.ensureNumber(bestSnapY);
        }
        
        return { x: newX, y: newY, appliedSnaps };
    }

    updatePosition = ({selection, event}) => {
        // 计算新位置（通过修改x、y实现移动）
        const transform = this.d3Instance.zoomTransform(this.canvas.node());
        const point = this.d3Instance.pointer(event, this.canvas.node());
        
        // 正确计算反转变换的点
        const invertedX = (point[0] - transform.x) / transform.k;
        const invertedY = (point[1] - transform.y) / transform.k;
        
        let newX = this.ensureNumber(invertedX - this.dragOffset.x);
        let newY = this.ensureNumber(invertedY - this.dragOffset.y);
        
        // 确保坐标不会是负数
        newX = Math.max(0, newX);
        newY = Math.max(0, newY);
        
        // 计算移动速度
        const currentTime = Date.now();
        const timeDelta = currentTime - this.lastTime;
        const distance = Math.sqrt(
            Math.pow(newX - this.lastPosition.x, 2) + 
            Math.pow(newY - this.lastPosition.y, 2)
        );
        const speed = timeDelta > 0 ? distance / timeDelta : 0;
        
        // 检测是否在移动
        if (distance > 0.5) { // 移动阈值
            this.isMoving = true;
            this.stopMoveTime = currentTime;
        } else if (currentTime - this.stopMoveTime > 100) { // 停止移动100ms后
            this.isMoving = false;
        }
        
        // 更新位置和时间
        this.lastPosition = { x: newX, y: newY };
        this.lastTime = currentTime;
        
        const elements = this.d3Instance.selectAll('.components');

        // 检查吸附
        const snaps = this.checkSnap(selection, elements);
        let appliedSnaps = [];

        // 应用吸附，但允许继续拖动
        if (snaps.length > 0) {
            const result = this.applySnaps(selection, snaps);
            
            // 智能吸附：只在非常接近时才应用吸附，否则保持正常移动速度
            const originalX = newX;
            const originalY = newY;
            
            // 计算与吸附位置的距离
            const distanceX = Math.abs(result.x - originalX);
            const distanceY = Math.abs(result.y - originalY);
            
            // 使用配置的阈值来决定是否应用吸附
            const snapThreshold = this.SNAP_DISTANCE * this.SNAP_THRESHOLD;
            
            // 只在距离很近且移动速度较慢时应用吸附
            if (distanceX <= snapThreshold && speed < this.MAX_SPEED_FOR_SNAP) {
                newX = result.x;
            }
            if (distanceY <= snapThreshold && speed < this.MAX_SPEED_FOR_SNAP) {
                newY = result.y;
            }
            
            appliedSnaps = result.appliedSnaps;
            
            // 绘制参考线
            this.guideline.draw(appliedSnaps, selection);
        } else {
            // 清除参考线
            this.guideline.clear();
        }

        return {
            x: newX,
            y: newY,
            appliedSnaps
        }
    }

}